package junior.util.io;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.Enumeration;
import java.util.zip.ZipInputStream;

import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipFile;
import org.apache.tools.zip.ZipOutputStream;

public class ZIPUtils {
    /**
     * ZIP压缩
     * @param files 将要压缩的文件或目录
     * @param zipFile 压缩包文件
     * @return 返回压缩前的文件总大小
     * @throws Exception
     */
    public static long zip(File[] files, File zipFile) throws Exception {
        return zip(files, zipFile, -1);
    }
    /**
     * ZIP压缩
     * @param files 将要压缩的文件或目录
     * @param zipFile 压缩包文件
     * @param compressLevel 压缩等级（0-9）
     * @return 返回压缩前的文件总大小
     * @throws Exception
     */
    public static long zip(File[] files, File zipFile, int compressLevel) throws Exception {
        return zip(files, new FileOutputStream(zipFile), compressLevel);
    }
    /**
     * ZIP压缩
     * @param files 将要压缩的文件或目录
     * @param os 压缩输出流
     * @return 返回压缩后的文件大小
     * @throws Exception
     */
    public static long zip(File[] files, OutputStream os) throws Exception {
        return zip(files, os, -1);
    }
    /**
     * ZIP压缩
     * @param files 将要压缩的文件或目录
     * @param os 压缩输出流
     * @param compressLevel 压缩等级（0-9）
     * @return 返回压缩前的文件总大小
     * @throws Exception
     */
    public static long zip(File[] files, OutputStream os, int compressLevel) throws Exception {
        ZipOutputStream zos = null;
        long total = 0;
        try {
            zos = new ZipOutputStream(os);
            if (compressLevel != -1) {
                zos.setLevel(compressLevel);
            }
            for (File f : files) {
                total += doZip(f, null, zos);
            }
            return total;
        } finally {
            if (zos != null) {try{zos.close();}catch(Exception e){}}
        }
    }
    
    private static long doZip(File file, String path, ZipOutputStream zos) throws Exception {
        long total = 0;
        String entryName = file.getName();
        if (path != null) {
            entryName = path + File.separator + entryName;
        }
        
        if (file.isDirectory()) {
            zos.putNextEntry(new ZipEntry(entryName+File.separator));
            for (File f : file.listFiles()) {
                total += doZip(f, entryName, zos);
            }
        } else {
            zos.putNextEntry(new ZipEntry(entryName));
            BufferedInputStream bis = null;
            try {
                bis = new BufferedInputStream(new FileInputStream(file));
                int len = 0;
                byte[] buffer = new byte[10240];
                while ((len = bis.read(buffer)) != -1) {
                    total += len;
                    zos.write(buffer, 0, len);
                }
                zos.flush();
            } finally {
                if (bis != null) {try{bis.close();}catch(Exception e){}}
            }
            zos.closeEntry();
        }
        return total;
    }

    /**
     * 
     * @param zipFile zipFileIP压缩文件
     * @param dir 文件解压后存放的目录
     * @param excludeOverrideFiles
     * @return 返回解压后的文件总大小
     * @throws Exception
     */
    public static long unzip(File zipFile, File dir, String... excludeOverrideFiles) throws Exception {
        return unzip("utf-8", zipFile, dir, null, excludeOverrideFiles);
    }
    
    public static long unzip(String encoding, File zipFile, File dir, String... excludeOverrideFiles) throws Exception {
    	return unzip(encoding, zipFile, dir, null, excludeOverrideFiles);
    }

    public static long unzip(File zipFile, File dir, FileFilter filter, String... excludeOverrideFiles) throws Exception {
    	return unzip("UTF-8", zipFile, dir, filter, excludeOverrideFiles);
    }
    /**
     * ZIP解压缩
     * @param zipFile ZIP压缩文件
     * @param dir 文件解压后存放的目录
     * @param filter 文件过滤器
     * @param excludeOverrideFiles 
     * @return 返回解压后的文件总大小
     * @throws Exception
     */
    public static long unzip(String encoding, File zipFile, File dir, FileFilter filter, String... excludeOverrideFiles) throws Exception {
        ZipFile  zis = null;
        long total = 0;
        try {
            zis = new ZipFile(zipFile, encoding);
            ZipEntry entry = null;
            Enumeration<ZipEntry> enums = zis.getEntries();
            while (enums.hasMoreElements()) {
                entry = enums.nextElement();
                String entryName = entry.getName();
                if (filter != null && ! filter.accept(new File(entryName))) {
                    continue;
                }
                
                String filePath = dir.getAbsolutePath() + File.separator + entryName;
                
                if (entry.isDirectory()) { //如果是一个目录
                    FileUtils.mkdir(new File(filePath));
                    continue;
                }
                
                tryMkdir(dir, entryName);
                
                if (new File(filePath).exists() && excludeOverrideFiles != null 
                        && excludeOverrideFiles.length > 0) {
                    int idx = entryName.lastIndexOf(File.separator);
                    String filename = entryName;
                    if (idx != -1) {
                        filename = entryName.substring(idx+1);
                    }
                    boolean exclude = false;
                    for (String s : excludeOverrideFiles) {
                        if (s.equals(filename)) {
                            exclude = true;
                            break;
                        }
                    }
                    if (exclude) {
                        continue;
                    }
                }
                
                BufferedOutputStream bos = null;
                BufferedInputStream bis = null;
                try {
                    bos = new BufferedOutputStream(new FileOutputStream(filePath));
                    bis = new BufferedInputStream(zis.getInputStream(entry));
                    FileUtils.pipeStream(bis, bos);
                } finally {
                    if (bos != null) {try{bos.close();}catch(Exception e){}}
                    if (bis != null) {try{bos.close();}catch(Exception e){}}
                }
            }
            return total;
        } finally {
            if (zis != null) {try{zis.close();}catch(Exception e){}}
        }
    }
    /**
	 * ZIP解压缩
	 * @param is 压缩输入流
	 * @param dir 文件解压后存放的目录
	 * @throws Exception
	 */
    public static long unzip(InputStream is, File dir, String... excludeOverrideFiles) throws Exception {
    	ZipInputStream  zis = null;
        long total = 0;
        try {
            zis = new ZipInputStream(is, Charset.forName("UTF-8"));
            java.util.zip.ZipEntry entry = null;
            while ((entry = zis.getNextEntry()) != null) {
                String entryName = entry.getName();
                
                String filePath = FileUtils.switchPathSeparator(dir.getAbsolutePath() + File.separator + entryName);
                
                if (entry.isDirectory()) { //如果是一个目录
                    FileUtils.mkdir(new File(filePath));
                    continue;
                }
                
                tryMkdir(dir, entryName);
                
                if (new File(filePath).exists() && excludeOverrideFiles != null 
                        && excludeOverrideFiles.length > 0) {
                    int idx = entryName.lastIndexOf(File.separator);
                    String filename = entryName;
                    if (idx != -1) {
                        filename = entryName.substring(idx+1);
                    }
                    boolean exclude = false;
                    for (String s : excludeOverrideFiles) {
                        if (s.equals(filename)) {
                            exclude = true;
                            break;
                        }
                    }
                    if (exclude) {
                    	zis.closeEntry();
                        continue;
                    }
                }
                
                BufferedOutputStream bos = null;
                BufferedInputStream bis = null;
                try {
                    bos = new BufferedOutputStream(new FileOutputStream(filePath));
                    bis = new BufferedInputStream(zis);
                    FileUtils.pipeStream(bis, bos);
                } finally {
                    if (bos != null) {try{bos.close();}catch(Exception e){}}
                    if (bis != null) {try{bos.close();}catch(Exception e){}}
                }
            	zis.closeEntry();
            }
            return total;
        } finally {
			zis.close();
            if (zis != null) {try{zis.close();}catch(Exception e){}}
        }
    }
    
    //尝试创建文件夹
    private static void tryMkdir(File parent, String filePath) {
        filePath = FileUtils.switchPathSeparator(filePath);
        int idx = filePath.lastIndexOf(File.separator);
        if (idx != -1) {
            String path = filePath.substring(0, idx);
            File file = new File(parent.getAbsolutePath() + File.separator + path);
            FileUtils.mkdir(file);
        }
    }
    
}
